package com.foreverwin.jzymes.framework.websocket;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.foreverwin.jzymes.framework.event.AppEvent;
import com.foreverwin.jzymes.framework.exception.BusinessException;
import com.foreverwin.jzymes.framework.util.SpringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.event.ApplicationEventMulticaster;
import org.springframework.web.context.support.GenericWebApplicationContext;

import java.io.IOException;
import java.util.List;

public abstract class TextMessageWebSocketWraper implements TextMessageWebSocket {

    private Connection connection;
    private String channel;
    private String mode = null;
    private String messageType = null;
    public List<String> events;

    @Override
    public void onMessage( String message ) {
        try{

            JSONObject requestParams = null;
            JSONObject responseBody = null;

            JSONObject messageObj = JSON.parseObject( message );
            mode = (String) messageObj.getOrDefault( "MODE", "P2P" );
            messageType = messageObj.getString( "MESSAGE_TYPE" );
            requestParams = messageObj.getJSONObject( "PARAM" );

            if( StringUtils.isBlank( messageType ) ){
                throw BusinessException.build( "Message must contain MESSAGE_TYPE" );
            }

            responseBody = doReceiveAndReply( messageType, requestParams );
            if( responseBody != null ){
                if( "P2P".equals( mode ) ){
                    sendMessage( responseBody );
                }else{
                    WebSocketServer.sendMessageToChannel( channel, messageType, responseBody );
                }
            }

        } catch (Exception e) {
            sendError( e.getMessage() );
        }
    }

    @Override
    public void onApplicationEvent(AppEvent appEvent) {
        if( events != null && events.contains( appEvent.getName() ) ){
            onAppEvent( appEvent );
        }
    }

    @Override
    public void onOpen(Connection connection) {
        this.connection = connection;

        if( getEvents() != null && getEvents().size() > 0 ){
            ApplicationContext applicationContext = SpringUtils.getApplicationContext();
            if( applicationContext instanceof GenericWebApplicationContext){
                GenericWebApplicationContext webApplicationContext = (GenericWebApplicationContext) applicationContext;
                webApplicationContext.addApplicationListener( this );
            }
        }
        WebSocketServer.registerWebSocket( this.channel, this.connection );

        doAfterOpen( connection );
    }

    @Override
    public void onClose(int i, String s) {

        ApplicationContext applicationContext = SpringUtils.getApplicationContext();
        if( applicationContext instanceof GenericWebApplicationContext){
            GenericWebApplicationContext webApplicationContext = (GenericWebApplicationContext) applicationContext;
            ConfigurableListableBeanFactory beanFactory = webApplicationContext.getBeanFactory();
            ApplicationEventMulticaster applicationEventMulticaster = beanFactory.getBean("applicationEventMulticaster", ApplicationEventMulticaster.class);
            applicationEventMulticaster.removeApplicationListener( this );
        }

        WebSocketServer.removeWebSocket( this.channel,this.connection );

        doAfterClose();
    }

    public void sendMessage( JSONObject messageBody ){
        try {
            JSONObject message = new JSONObject();
            message.put( "MODE", mode );
            message.put( "MESSAGE_TYPE", messageType );
            message.put( "CODE", 0 );
            message.put( "ERROR_MSG", "" );
            message.put( "MESSAGE", messageBody );

            this.connection.sendMessage( message.toString() );
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void sendMessage( String messageType, JSONObject messageBody ){
        try {
            JSONObject message = new JSONObject();
            message.put( "MODE", mode );
            message.put( "MESSAGE_TYPE", messageType );
            message.put( "CODE", 0 );
            message.put( "ERROR_MSG", "" );
            message.put( "MESSAGE", messageBody );

            this.connection.sendMessage( message.toString() );
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void sendError( String errorMessage ){
        try {
            JSONObject message = new JSONObject();
            message.put( "MODE", mode );
            message.put( "MESSAGE_TYPE", messageType );
            message.put( "CODE", 1 );
            message.put( "ERROR_MSG", errorMessage );

            this.connection.sendMessage( message.toString() );
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void sendMessage( String message ){
        try {
            this.connection.sendMessage( message );
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void publishMessage( String message ){
        WebSocketServer.sendMessageToChannel( this.channel, message );
    }

    @Override
    public String getChannel() {
        return this.channel;
    }

    @Override
    public void setChannel(String channel) {
        this.channel = channel;
    }

    public List<String> getEvents(){
        return this.events;
    }
}
